Apgūstiet React createRef imperatīvai DOM un komponentu instanču manipulācijai. Uzziniet, kad un kā to efektīvi izmantot klašu komponentos fokusam, medijiem un trešo pušu integrācijām.
React createRef: Visaptverošs ceļvedis tiešai komponentu un DOM elementu mijiedarbībai
Plašajā un bieži vien sarežģītajā mūsdienu tīmekļa izstrādes ainavā React ir kļuvis par dominējošu spēku, galvenokārt pateicoties tā deklaratīvajai pieejai lietotāja saskarņu veidošanai. Šī paradigma mudina izstrādātājus aprakstīt, kā viņu lietotāja saskarnei vajadzētu izskatīties, pamatojoties uz datiem, nevis noteikt, kā sasniegt šo vizuālo stāvokli ar tiešām DOM manipulācijām. Šī abstrakcija ir būtiski vienkāršojusi lietotāja saskarnes izstrādi, padarot lietojumprogrammas paredzamākas, vieglāk saprotamas un ļoti veiktspējīgas.
Tomēr reālā tīmekļa lietojumprogrammu pasaule reti ir pilnībā deklaratīva. Ir specifiski, bet bieži sastopami scenāriji, kuros tieša mijiedarbība ar pamatā esošo DOM (Document Object Model) elementu vai klases komponenta instanci kļūst ne tikai ērta, bet absolūti nepieciešama. Šīs "avārijas izejas" no React deklaratīvās plūsmas ir pazīstamas kā refs. Starp dažādiem mehānismiem, ko React piedāvā šo atsauču izveidei un pārvaldībai, React.createRef() ir fundamentāls API, kas īpaši svarīgs izstrādātājiem, kuri strādā ar klašu komponentiem.
Šī visaptverošā rokasgrāmata ir paredzēta kā jūsu galvenais resurss React.createRef() izpratnei, ieviešanai un apgūšanai. Mēs uzsāksim detalizētu tā mērķa izpēti, iedziļināsimies tā sintaksē un praktiskajos pielietojumos, izskaidrosim labākās prakses un atšķirsim to no citām ref pārvaldības stratēģijām. Neatkarīgi no tā, vai esat pieredzējis React izstrādātājs, kurš vēlas nostiprināt savu izpratni par imperatīvām mijiedarbībām, vai iesācējs, kurš vēlas apgūt šo svarīgo konceptu, šis raksts sniegs jums zināšanas, lai veidotu stabilākas, veiktspējīgākas un globāli pieejamas React lietojumprogrammas, kas eleganti risina mūsdienu lietotāju pieredzes sarežģītās prasības.
Izpratne par Refs React: Tilts starp deklaratīvo un imperatīvo pasauli
Savā būtībā React atbalsta deklaratīvu programmēšanas stilu. Jūs definējat savus komponentus, to stāvokli un to, kā tie tiek renderēti. Pēc tam React pārņem vadību, efektīvi atjauninot faktisko pārlūkprogrammas DOM, lai atspoguļotu jūsu deklarēto lietotāja saskarni. Šis abstrakcijas slānis ir ārkārtīgi spēcīgs, pasargājot izstrādātājus no tiešas DOM manipulācijas sarežģītības un veiktspējas problēmām. Tieši tāpēc React lietojumprogrammas bieži šķiet tik plūdenas un atsaucīgas.
Vienvirziena datu plūsma un tās ierobežojumi
React arhitektūras spēks slēpjas tā vienvirziena datu plūsmā. Dati paredzami plūst uz leju no vecākkomponentiem uz bērnkomponentiem, izmantojot props, un stāvokļa izmaiņas komponentā izraisa atkārtotu renderēšanu, kas izplatās pa tā apakškoku. Šis modelis veicina paredzamību un ievērojami atvieglo atkļūdošanu, jo jūs vienmēr zināt, no kurienes dati nāk un kā tie ietekmē lietotāja saskarni. Tomēr ne katra mijiedarbība perfekti atbilst šai no augšas uz leju vērstajai datu plūsmai.
Apsveriet šādus scenārijus:
- Programmatiska fokusa iestatīšana ievades laukam, kad lietotājs pārvietojas uz formu.
play()vaipause()metožu izsaukšana<video>elementam.- Precīzu pikseļu izmēru mērīšana renderētam
<div>, lai dinamiski pielāgotu izkārtojumu. - Sarežģītas trešās puses JavaScript bibliotēkas (piemēram, diagrammu bibliotēkas kā D3.js vai karšu vizualizācijas rīka) integrēšana, kas sagaida tiešu piekļuvi DOM konteinerim.
Šīs darbības pēc savas būtības ir imperatīvas – tās ietver tiešu komandu elementam kaut ko darīt, nevis tikai tā vēlamā stāvokļa deklarēšanu. Lai gan React deklaratīvais modelis bieži var abstrahēt daudzas imperatīvās detaļas, tas pilnībā nenovērš nepieciešamību pēc tām. Tieši šeit noder refs, nodrošinot kontrolētu avārijas izeju, lai veiktu šīs tiešās mijiedarbības.
Kad lietot Refs: Imperatīvās un deklaratīvās mijiedarbības navigācija
Vissvarīgākais princips, strādājot ar refs, ir lietot tos taupīgi un tikai tad, kad tas ir absolūti nepieciešams. Ja uzdevumu var paveikt, izmantojot React standarta deklaratīvos mehānismus (stāvokli un props), tam vienmēr vajadzētu būt jūsu vēlamajai pieejai. Pārmērīga paļaušanās uz refs var novest pie koda, kas ir grūtāk saprotams, uzturams un atkļūdojams, tādējādi mazinot pašas React sniegtās priekšrocības.
Tomēr situācijās, kas patiešām prasa tiešu piekļuvi DOM mezglam vai komponenta instancei, refs ir pareizs un paredzēts risinājums. Šeit ir detalizētāks piemērotu lietošanas gadījumu sadalījums:
- Fokusa, teksta iezīmēšanas un multivides atskaņošanas pārvaldība: Šie ir klasiski piemēri, kur nepieciešama imperatīva mijiedarbība ar elementiem. Padomājiet par automātisku fokusa iestatīšanu meklēšanas joslai lapas ielādes brīdī, visa teksta iezīmēšanu ievades laukā vai audio vai video atskaņotāja atskaņošanas kontroli. Šīs darbības parasti izraisa lietotāja notikumi vai komponenta dzīves cikla metodes, nevis vienkārši mainot props vai stāvokli.
- Imperatīvu animāciju ierosināšana: Lai gan daudzas animācijas var pārvaldīt deklaratīvi ar CSS pārejām/animācijām vai React animāciju bibliotēkām, dažas sarežģītas, augstas veiktspējas animācijas, īpaši tās, kas saistītas ar HTML Canvas API, WebGL, vai prasa smalku kontroli pār elementu īpašībām, kuras vislabāk pārvaldīt ārpus React renderēšanas cikla, var prasīt refs.
- Integrācija ar trešo pušu DOM bibliotēkām: Daudzas cienījamas JavaScript bibliotēkas (piemēram, D3.js, Leaflet kartēm, dažādi mantoti lietotāja saskarnes rīkkopa) ir izstrādātas, lai tieši manipulētu ar konkrētiem DOM elementiem. Refs nodrošina būtisku tiltu, ļaujot React renderēt konteinera elementu un pēc tam piešķirot trešās puses bibliotēkai piekļuvi šim konteinerim tās pašas imperatīvās renderēšanas loģikai.
-
Elementa izmēru vai pozīcijas mērīšana: Lai ieviestu sarežģītus izkārtojumus, virtualizāciju vai pielāgotu ritināšanas uzvedību, bieži ir nepieciešama precīza informācija par elementa izmēru, tā pozīciju attiecībā pret skatlogu vai tā ritināšanas augstumu. API, piemēram,
getBoundingClientRect(), ir pieejami tikai faktiskajiem DOM mezgliem, padarot refs neaizstājamus šādiem aprēķiniem.
Un otrādi, jums vajadzētu izvairīties no refs izmantošanas uzdevumiem, kurus var paveikt deklaratīvi. Tas ietver:
- Komponenta stila modificēšanu (izmantojiet stāvokli nosacījuma stilam).
- Elementa teksta satura maiņu (nododiet kā prop vai atjauniniet stāvokli).
- Sarežģītu komponentu komunikāciju (props un atzvanu funkcijas parasti ir labākas).
- Jebkuru scenāriju, kurā mēģināt atkārtot stāvokļa pārvaldības funkcionalitāti.
Iedziļināšanās React.createRef(): Mūsdienīga pieeja klašu komponentiem
React.createRef() tika ieviests React 16.3, nodrošinot skaidrāku un tīrāku veidu, kā pārvaldīt refs, salīdzinot ar vecākām metodēm, piemēram, virknes refs (tagad novecojušas) un atzvanu refs (joprojām derīgas, bet bieži vien izvērstākas). Tas ir paredzēts kā galvenais ref izveides mehānisms klašu komponentiem, piedāvājot objektorientētu API, kas dabiski iederas klases struktūrā.
Sintakse un pamata lietojums: Trīs soļu process
Darbplūsma, izmantojot createRef(), ir vienkārša un ietver trīs galvenos soļus:
-
Izveidojiet Ref objektu: Jūsu klases komponenta konstruktorā inicializējiet ref instanci, izsaucot
React.createRef()un piešķirot tā atgriezto vērtību instances īpašībai (piemēram,this.myRef). -
Pievienojiet Ref: Jūsu komponenta
rendermetodē nododiet izveidoto ref objekturefatribūtam React elementam (vai nu HTML elementam, vai klases komponentam), uz kuru vēlaties atsaukties. -
Piekļūstiet mērķim: Kad komponents ir iemontēts, atsauces DOM mezgls vai komponenta instance būs pieejama caur jūsu ref objekta
.currentīpašību (piemēram,this.myRef.current).
import React from 'react';
class FocusInputOnMount extends React.Component {
constructor(props) {
super(props);
this.inputElementRef = React.createRef(); // 1. solis: Konstruktorā izveidojiet ref objektu
console.log('Constructor: Ref current value is initially:', this.inputElementRef.current); // null
}
componentDidMount() {
if (this.inputElementRef.current) {
this.inputElementRef.current.focus();
console.log('ComponentDidMount: Input focused. Current value:', this.inputElementRef.current.value);
}
}
handleButtonClick = () => {
if (this.inputElementRef.current) {
alert(`Input value: ${this.inputElementRef.current.value}`);
}
};
render() {
console.log('Render: Ref current value is:', this.inputElementRef.current); // Sākotnējā renderēšanā joprojām ir null
return (
<div style={{ padding: '20px', border: '1px solid #ccc', borderRadius: '8px' }}>
<h3>Automātiska fokusa iestatīšana ievades laukam</h3>
<label htmlFor="focusInput">Ievadiet savu vārdu:</label><br />
<input
id="focusInput"
type="text"
ref={this.inputElementRef} // 2. solis: Pievienojiet ref <input> elementam
placeholder="Jūsu vārds šeit..."
style={{ margin: '10px 0', padding: '8px', borderRadius: '4px', border: '1px solid #ddd' }}
/><br />
<button
onClick={this.handleButtonClick}
style={{ padding: '10px 15px', background: '#007bff', color: 'white', border: 'none', borderRadius: '5px', cursor: 'pointer' }}
>
Rādīt ievades vērtību
</button>
<p><em>Šis ievades lauks automātiski saņems fokusu, kad komponents ielādēsies.</em></p>
</div>
);
}
}
Šajā piemērā this.inputElementRef ir objekts, ko React pārvaldīs iekšēji. Kad <input> elements tiek renderēts un iemontēts DOM, React piešķir šo faktisko DOM mezglu this.inputElementRef.current. componentDidMount dzīves cikla metode ir ideāla vieta, kur mijiedarboties ar refs, jo tā garantē, ka komponents un tā bērni ir renderēti DOM un ka .current īpašība ir pieejama un aizpildīta.
Ref pievienošana DOM elementam: Tieša piekļuve DOM
Kad jūs pievienojat ref standarta HTML elementam (piemēram, <div>, <p>, <button>, <img>), jūsu ref objekta .current īpašība saturēs faktisko pamatā esošo DOM elementu. Tas dod jums neierobežotu piekļuvi visiem standarta pārlūkprogrammas DOM API, ļaujot veikt darbības, kas parasti ir ārpus React deklaratīvās kontroles. Tas ir īpaši noderīgi globālām lietojumprogrammām, kur precīzs izkārtojums, ritināšana vai fokusa pārvaldība var būt kritiska dažādās lietotāju vidēs un ierīču tipos.
import React from 'react';
class ScrollToElementExample extends React.Component {
constructor(props) {
super(props);
this.targetDivRef = React.createRef();
this.state = { showScrollButton: false };
}
componentDidMount() {
// Rādīt ritināšanas pogu tikai tad, ja ir pietiekami daudz satura, lai ritinātu
// Šī pārbaude arī nodrošina, ka ref jau ir aktuāls.
if (this.targetDivRef.current && window.innerHeight < document.body.scrollHeight) {
this.setState({ showScrollButton: true });
}
}
handleScrollToTarget = () => {
if (this.targetDivRef.current) {
// Izmantojot scrollIntoView plūstošai ritināšanai, plaši atbalstīts visās pārlūkprogrammās visā pasaulē.
this.targetDivRef.current.scrollIntoView({
behavior: 'smooth', // Animē ritināšanu labākai lietotāja pieredzei
block: 'start' // Izlīdzina elementa augšējo malu ar skatloga augšējo malu
});
console.log('Scrolled to target div!');
} else {
console.warn('Target div not yet available for scrolling.');
}
};
render() {
return (
<div style={{ padding: '15px' }}>
<h2>Ritināšana uz konkrētu elementu ar Ref</h2>
<p>Šis piemērs demonstrē, kā programmatiski ritināt uz DOM elementu, kas atrodas ārpus ekrāna.</p>
{this.state.showScrollButton && (
<button
onClick={this.handleScrollToTarget}
style={{ marginBottom: '20px', padding: '10px 20px', background: '#28a745', color: 'white', border: 'none', borderRadius: '5px', cursor: 'pointer' }}
>
Ritināt uz leju līdz mērķa zonai
</button>
)}
<div style={{ height: '1500px', background: '#f8f9fa', padding: '20px', marginBottom: '20px', border: '1px dashed #6c757d' }}>
<p>Viettura saturs, lai izveidotu vertikālu ritināšanas vietu.</p>
<p>Iedomājieties garus rakstus, sarežģītas formas vai detalizētus paneļus, kas prasa lietotājiem pārvietoties pa plašu saturu. Programmatiska ritināšana nodrošina, ka lietotāji var ātri sasniegt attiecīgās sadaļas bez manuālas piepūles, uzlabojot pieejamību un lietotāju plūsmu visās ierīcēs un ekrāna izmēros.</p>
<p>Šī tehnika ir īpaši noderīga daudzlapu formās, soli-pa-solim vedņos vai vienas lapas lietojumprogrammās ar dziļu navigāciju.</p>
</div>
<div
ref={this.targetDivRef} // Pievienojiet ref šeit
style={{
minHeight: '300px',
background: '#e9ecef',
padding: '30px',
border: '2px solid #007bff',
borderRadius: '10px',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
textAlign: 'center'
}}
>
<h3>Jūs esat sasniedzis mērķa zonu!</h3>
<p>Šī ir sadaļa, uz kuru mēs ritinājām programmatiski.</p>
<p>Spēja precīzi kontrolēt ritināšanas uzvedību ir kritiska, lai uzlabotu lietotāja pieredzi, īpaši mobilajās ierīcēs, kur ekrāna platība ir ierobežota un precīza navigācija ir vissvarīgākā.</p>
</div>
</div>
);
}
}
Šis piemērs lieliski ilustrē, kā createRef nodrošina kontroli pār pārlūkprogrammas līmeņa mijiedarbībām. Šādas programmatiskas ritināšanas iespējas ir kritiskas daudzās lietojumprogrammās, sākot no garas dokumentācijas navigācijas līdz lietotāju vadīšanai caur sarežģītām darbplūsmām. behavior: 'smooth' opcija scrollIntoView nodrošina patīkamu, animētu pāreju, uzlabojot lietotāja pieredzi universāli.
Ref pievienošana klašu komponentam: Mijiedarbība ar instancēm
Papildus vietējiem DOM elementiem, jūs varat arī pievienot ref klases komponenta instancei. Kad jūs to darāt, jūsu ref objekta .current īpašība saturēs pašu faktisko instancēto klases komponentu. Tas ļauj vecākkomponentam tieši izsaukt metodes, kas definētas bērnkomponenta klasē, vai piekļūt tā instances īpašībām. Lai gan šī iespēja ir spēcīga, tā jālieto ar lielu piesardzību, jo tā ļauj pārkāpt tradicionālo vienvirziena datu plūsmu, potenciāli novedot pie mazāk paredzamas lietojumprogrammas uzvedības.
import React from 'react';
// Bērnkomponenta klase
class DialogBox extends React.Component {
constructor(props) {
super(props);
this.state = { isOpen: false, message: '' };
}
// Metode, kas pieejama vecākam caur ref
open(message) {
this.setState({ isOpen: true, message });
}
close = () => {
this.setState({ isOpen: false, message: '' });
};
render() {
if (!this.state.isOpen) return null;
return (
<div style={{
position: 'fixed', top: '50%', left: '50%', transform: 'translate(-50%, -50%)',
padding: '25px 35px', background: 'white', border: '1px solid #ddd', borderRadius: '8px',
boxShadow: '0 5px 15px rgba(0,0,0,0.2)', zIndex: 1000, maxWidth: '400px', width: '90%', textAlign: 'center'
}}>
<h4>Ziņojums no vecākkomponenta</h4>
<p>{this.state.message}</p>
<button
onClick={this.close}
style={{ marginTop: '15px', padding: '8px 15px', background: '#dc3545', color: 'white', border: 'none', borderRadius: '5px', cursor: 'pointer' }}
>
Aizvērt
</button>
</div>
);
}
}
// Vecākkomponenta klase
class AppWithDialog extends React.Component {
constructor(props) {
super(props);
this.dialogRef = React.createRef();
}
handleOpenDialog = () => {
if (this.dialogRef.current) {
// Piekļūstiet bērnkomponenta instancei un izsauciet tās 'open' metodi
this.dialogRef.current.open('Sveiki no vecākkomponenta! Šis dialogs tika atvērts imperatīvi.');
}
};
render() {
return (
<div style={{ padding: '20px', textAlign: 'center' }}>
<h2>Vecāk-bērnu komunikācija caur Ref</h2>
<p>Šis piemērs demonstrē, kā vecākkomponents var imperatīvi kontrolēt sava bērnkomponenta klases metodi.</p>
<button
onClick={this.handleOpenDialog}
style={{ padding: '12px 25px', background: '#007bff', color: 'white', border: 'none', borderRadius: '6px', cursor: 'pointer', fontSize: '1.1em' }}
>
Atvērt imperatīvo dialogu
</button>
<DialogBox ref={this.dialogRef} /> // Pievienojiet ref klases komponenta instancei
</div>
);
}
}
Šeit AppWithDialog var tieši izsaukt DialogBox komponenta open metodi caur tā ref. Šis modelis var būt noderīgs, lai ierosinātu darbības, piemēram, modāla loga rādīšanu, formas atiestatīšanu vai programmatisku ārējo lietotāja saskarnes elementu kontroli, kas ir iekapsulēti bērnkomponentā. Tomēr parasti ieteicams dot priekšroku uz props balstītai komunikācijai lielākajai daļai scenāriju, nododot datus un atzvanu funkcijas no vecāka uz bērnu, lai saglabātu skaidru un paredzamu datu plūsmu. Izmantojiet refs bērnkomponentu metodēm tikai tad, ja šīs darbības ir patiesi imperatīvas un neiederās tipiskajā prop/state plūsmā.
Ref pievienošana funkcionālam komponentam (Būtiska atšķirība)
Izplatīts nepareizs priekšstats un svarīgs atšķirības punkts ir tas, ka jūs nevarat tieši pievienot ref, izmantojot createRef(), funkcionālam komponentam. Funkcionālajiem komponentiem pēc to būtības nav instanču tādā pašā veidā kā klašu komponentiem. Ja mēģināsiet piešķirt ref tieši funkcionālam komponentam (piemēram, <MyFunctionalComponent ref={this.myRef} />), React izstrādes režīmā izdos brīdinājumu, jo nav komponenta instances, ko piešķirt .current.
Ja jūsu mērķis ir ļaut vecākkomponentam (kas varētu būt klases komponents, izmantojot createRef, vai funkcionāls komponents, izmantojot useRef) piekļūt DOM elementam, kas renderēts iekšā funkcionālā bērnkomponentā, jums jāizmanto React.forwardRef. Šis augstākās kārtas komponents ļauj funkcionāliem komponentiem atklāt ref konkrētam DOM mezglam vai imperatīvam rokturim sevī.
Alternatīvi, ja strādājat funkcionāla komponenta iekšienē un jums ir nepieciešams izveidot un pārvaldīt ref, piemērots mehānisms ir useRef āķis (hook), kas tiks īsi apskatīts vēlāk salīdzināšanas sadaļā. Ir svarīgi atcerēties, ka createRef ir fundamentāli saistīts ar klašu komponentiem un to uz instancēm balstīto dabu.
Piekļuve DOM mezglam vai komponenta instancei: `.current` īpašības skaidrojums
Ref mijiedarbības kodols ir ap .current īpašību, kas pieder React.createRef() izveidotajam ref objektam. Tās dzīves cikla un satura izpratne ir būtiska efektīvai ref pārvaldībai.
`.current` īpašība: Jūsu vārti uz imperatīvo kontroli
.current īpašība ir maināms objekts, ko pārvalda React. Tas kalpo kā tieša saite uz atsauces elementu vai komponenta instanci. Tā vērtība mainās komponenta dzīves cikla laikā:
-
Inicializācija: Kad jūs pirmo reizi izsaucat
React.createRef()konstruktorā, tiek izveidots ref objekts, un tā.currentīpašība tiek inicializēta uznull. Tas ir tāpēc, ka šajā posmā komponents vēl nav renderēts, un nav DOM elementa vai komponenta instances, uz kuru ref varētu norādīt. -
Iemontēšana: Kad komponents tiek renderēts DOM un elements ar
refatribūtu ir izveidots, React piešķir faktisko DOM mezglu vai klases komponenta instanci jūsu ref objekta.currentīpašībai. Tas parasti notiek uzreiz pēcrendermetodes pabeigšanas un pirmscomponentDidMountizsaukšanas. TāpēccomponentDidMountir drošākā un visbiežāk izmantotā vieta, lai piekļūtu un mijiedarbotos ar.current. -
Demontēšana: Kad komponents tiek demontēts no DOM, React automātiski atiestata
.currentīpašību atpakaļ uznull. Tas ir svarīgi, lai novērstu atmiņas noplūdes un nodrošinātu, ka jūsu lietojumprogramma netur atsauces uz elementiem, kas vairs nepastāv DOM. -
Atjaunināšana: Retos gadījumos, kad
refatribūts tiek mainīts elementam atjaunināšanas laikā, vecā refcurrentīpašība tiks iestatīta uznullpirms jaunā refcurrentīpašības iestatīšanas. Šī uzvedība ir retāk sastopama, bet svarīgi to atzīmēt sarežģītu dinamisku ref piešķiršanu gadījumā.
import React from 'react';
class RefLifecycleLogger extends React.Component {
constructor(props) {
super(props);
this.myDivRef = React.createRef();
console.log('1. Constructor: this.myDivRef.current is', this.myDivRef.current); // null
}
componentDidMount() {
console.log('3. componentDidMount: this.myDivRef.current is', this.myDivRef.current); // Faktiskais DOM elements
if (this.myDivRef.current) {
this.myDivRef.current.style.backgroundColor = '#d4edda'; // Imperatīvs stils demonstrācijai
this.myDivRef.current.innerText += ' - Ref ir aktīvs!';
}
}
componentDidUpdate(prevProps, prevState) {
console.log('4. componentDidUpdate: this.myDivRef.current is', this.myDivRef.current); // Faktiskais DOM elements (pēc atjauninājumiem)
}
componentWillUnmount() {
console.log('5. componentWillUnmount: this.myDivRef.current is', this.myDivRef.current); // Faktiskais DOM elements (tieši pirms nullēšanas)
// Šajā brīdī varētu veikt tīrīšanu, ja nepieciešams
}
render() {
// Sākotnējā renderēšanā šis.myDivRef.current joprojām ir null, jo DOM vēl nav izveidots.
// Nākamajās renderēšanās (pēc iemontēšanas) tas saturēs elementu.
console.log('2. Render: this.myDivRef.current is', this.myDivRef.current);
return (
<div
ref={this.myDivRef}
style={{ padding: '20px', border: '1px solid #28a745', margin: '20px', minHeight: '80px', display: 'flex', alignItems: 'center' }}
>
<p>Šis ir div, kuram pievienots ref.</p>
</div>
);
}
}
Vērojot konsoles izvadi RefLifecycleLogger, tiek sniegts skaidrs ieskats, kad this.myDivRef.current kļūst pieejams. Ir svarīgi vienmēr pārbaudīt, vai this.myDivRef.current nav null, pirms mēģināt ar to mijiedarboties, īpaši metodēs, kas varētu darboties pirms iemontēšanas vai pēc demontēšanas.
Ko var saturēt `.current`? Jūsu Ref satura izpēte
Vērtības tips, ko satur current, ir atkarīgs no tā, kam jūs pievienojat ref:
-
Pievienojot HTML elementam (piemēram,
<div>,<input>):.currentīpašība saturēs faktisko pamatā esošo DOM elementu. Tas ir vietējs JavaScript objekts, kas nodrošina piekļuvi visam tā DOM API klāstam. Piemēram, ja pievienojat ref<input type="text">,.currentbūsHTMLInputElementobjekts, kas ļauj izsaukt metodes, piemēram,.focus(), lasīt īpašības, piemēram,.value, vai modificēt atribūtus, piemēram,.placeholder. Šis ir visbiežāk sastopamais refs lietošanas gadījums.this.inputRef.current.focus();
this.videoRef.current.play();
const { width, height } = this.divRef.current.getBoundingClientRect(); -
Pievienojot klases komponentam (piemēram,
<MyClassComponent />):.currentīpašība saturēs šī klases komponenta instanci. Tas nozīmē, ka jūs varat tieši izsaukt metodes, kas definētas šajā bērnkomponentā (piemēram,childRef.current.someMethod()), vai pat piekļūt tā stāvoklim vai props (lai gan tieša piekļuve bērna stāvoklim/props caur ref parasti nav ieteicama, dodot priekšroku props un stāvokļa atjauninājumiem). Šī iespēja ir spēcīga, lai ierosinātu specifisku uzvedību bērnkomponentos, kas neiederās standarta uz props balstītajā mijiedarbības modelī.this.childComponentRef.current.resetForm();
// Reti, bet iespējams: console.log(this.childComponentRef.current.state.someValue); -
Pievienojot funkcionālam komponentam (caur
forwardRef): Kā jau iepriekš minēts, refs nevar pievienot tieši funkcionāliem komponentiem. Tomēr, ja funkcionāls komponents ir ietīts arReact.forwardRef, tad.currentīpašība saturēs jebkuru vērtību, ko funkcionālais komponents skaidri atklāj caur pārsūtīto ref. Tas parasti ir DOM elements funkcionālā komponenta iekšienē vai objekts, kas satur imperatīvas metodes (izmantojotuseImperativeHandleāķi kopā arforwardRef).// Vecākkomponentā myForwardedRef.current būtu atklātais DOM mezgls vai objekts
this.myForwardedRef.current.focus();
this.myForwardedRef.current.customResetMethod();
Praktiski `createRef` pielietojuma piemēri darbībā
Lai patiesi aptvertu React.createRef() lietderību, izpētīsim detalizētākus, globāli nozīmīgus scenārijus, kuros tas izrādās neaizstājams, pārsniedzot vienkāršu fokusa pārvaldību.
1. Fokusa, teksta iezīmēšanas vai multivides atskaņošanas pārvaldība dažādās kultūrās
Šie ir galvenie imperatīvās lietotāja saskarnes mijiedarbības piemēri. Iedomājieties daudzpakāpju formu, kas paredzēta globālai auditorijai. Pēc tam, kad lietotājs pabeidz vienu sadaļu, jūs, iespējams, vēlēsities automātiski pārvietot fokusu uz nākamās sadaļas pirmo ievades lauku neatkarīgi no valodas vai noklusējuma teksta virziena (no kreisās uz labo vai no labās uz kreiso). Refs nodrošina nepieciešamo kontroli.
import React from 'react';
class DynamicFocusForm extends React.Component {
constructor(props) {
super(props);
this.firstNameRef = React.createRef();
this.lastNameRef = React.createRef();
this.emailRef = React.createRef();
this.state = { currentStep: 1 };
}
componentDidMount() {
// Fokusēt uz pirmo ievades lauku, kad komponents iemontējas
this.firstNameRef.current.focus();
}
handleNextStep = (nextRef) => {
this.setState(prevState => ({ currentStep: prevState.currentStep + 1 }), () => {
// Pēc stāvokļa atjaunināšanas un komponenta atkārtotas renderēšanas, fokusēt nākamo ievades lauku
if (nextRef.current) {
nextRef.current.focus();
}
});
};
render() {
const { currentStep } = this.state;
const formSectionStyle = { border: '1px solid #0056b3', padding: '20px', margin: '15px 0', borderRadius: '8px', background: '#e7f0fa' };
const inputStyle = { width: '100%', padding: '10px', margin: '8px 0', border: '1px solid #ccc', borderRadius: '4px' };
const buttonStyle = { padding: '10px 20px', background: '#007bff', color: 'white', border: 'none', borderRadius: '5px', cursor: 'pointer', marginTop: '10px' };
return (
<div style={{ maxWidth: '600px', margin: '30px auto', padding: '25px', boxShadow: '0 4px 12px rgba(0,0,0,0.1)', borderRadius: '10px', background: 'white' }}>
<h2>Daudzpakāpju forma ar Ref pārvaldītu fokusu</h2>
<p>Pašreizējais solis: <strong>{currentStep}</strong></p>
{currentStep === 1 && (
<div style={formSectionStyle}>
<h3>Personas dati</h3>
<label htmlFor="firstName">Vārds:</label>
<input id="firstName" type="text" ref={this.firstNameRef} style={inputStyle} placeholder="piem., Jānis" />
<label htmlFor="lastName">Uzvārds:</label>
<input id="lastName" type="text" ref={this.lastNameRef} style={inputStyle} placeholder="piem., Bērziņš" />
<button onClick={() => this.handleNextStep(this.emailRef)} style={buttonStyle}>Nākamais →</button>
</div>
)}
{currentStep === 2 && (
<div style={formSectionStyle}>
<h3>Kontaktinformācija</h3>
<label htmlFor="email">E-pasts:</label>
<input id="email" type="email" ref={this.emailRef} style={inputStyle} placeholder="piem., janis.berzins@example.com" />
<p>... citi kontaktu lauki ...</p>
<button onClick={() => alert('Forma iesniegta!')} style={buttonStyle}>Iesniegt</button>
</div>
)}
<p><em>Šī mijiedarbība būtiski uzlabo pieejamību un lietotāja pieredzi, īpaši lietotājiem, kuri globāli paļaujas uz tastatūras navigāciju vai palīgtehnoloģijām.</em></p>
</div>
);
}
}
Šis piemērs demonstrē praktisku daudzpakāpju formu, kurā createRef tiek izmantots, lai programmatiski pārvaldītu fokusu. Tas nodrošina plūstošu un pieejamu lietotāja ceļu, kas ir būtisks apsvērums lietojumprogrammām, kuras tiek izmantotas dažādos valodu un kultūras kontekstos. Līdzīgi, multivides atskaņotājiem, refs ļauj veidot pielāgotas vadīklas (atskaņot, pauzēt, skaļums, meklēt), kas tieši mijiedarbojas ar HTML5 <video> vai <audio> elementu vietējiem API, nodrošinot konsekventu pieredzi neatkarīgi no pārlūkprogrammas noklusējuma iestatījumiem.
2. Imperatīvu animāciju un Canvas mijiedarbību ierosināšana
Lai gan deklaratīvās animāciju bibliotēkas ir lieliskas daudziem lietotāja saskarnes efektiem, dažas sarežģītas animācijas, īpaši tās, kas izmanto HTML5 Canvas API, WebGL vai prasa smalku kontroli pār elementu īpašībām, kuras vislabāk pārvaldīt ārpus React renderēšanas cikla, gūst lielu labumu no refs. Piemēram, reāllaika datu vizualizācijas vai spēles izveide uz Canvas elementa ietver zīmēšanu tieši uz pikseļu bufera, kas ir pēc būtības imperatīvs process.
import React from 'react';
class CanvasAnimator extends React.Component {
constructor(props) {
super(props);
this.canvasRef = React.createRef();
this.animationFrameId = null;
}
componentDidMount() {
this.startAnimation();
}
componentWillUnmount() {
this.stopAnimation();
}
startAnimation = () => {
const canvas = this.canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext('2d');
let angle = 0;
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
const radius = 50;
const animate = () => {
ctx.clearRect(0, 0, canvas.width, canvas.height); // Notīrīt audeklu
// Uzzīmēt rotējošu kvadrātu
ctx.save();
ctx.translate(centerX, centerY);
ctx.rotate(angle);
ctx.fillStyle = '#6f42c1';
ctx.fillRect(-radius / 2, -radius / 2, radius, radius);
ctx.restore();
angle += 0.05; // Palielināt leņķi rotācijai
this.animationFrameId = requestAnimationFrame(animate);
};
this.animationFrameId = requestAnimationFrame(animate);
};
stopAnimation = () => {
if (this.animationFrameId) {
cancelAnimationFrame(this.animationFrameId);
}
};
render() {
return (
<div style={{ textAlign: 'center', margin: '30px auto', border: '1px solid #ced4da', padding: '20px', borderRadius: '8px', background: '#f8f9fa' }}>
<h3>Imperatīva Canvas animācija ar createRef</h3>
<p>Šo canvas animāciju tieši kontrolē, izmantojot pārlūkprogrammas API, izmantojot ref.</p>
<canvas ref={this.canvasRef} width="300" height="200" style={{ border: '1px solid #adb5bd', background: 'white' }}>
Jūsu pārlūkprogramma neatbalsta HTML5 canvas tagu.
</canvas>
<p><em>Šāda tieša kontrole ir vitāli svarīga augstas veiktspējas grafikai, spēlēm vai specializētām datu vizualizācijām, ko izmanto dažādās nozarēs visā pasaulē.</em></p>
</div>
);
}
}
Šis komponents nodrošina canvas elementu un izmanto ref, lai iegūtu tiešu piekļuvi tā 2D renderēšanas kontekstam. Animācijas cikls, ko darbina `requestAnimationFrame`, pēc tam imperatīvi zīmē un atjaunina rotējošu kvadrātu. Šis modelis ir fundamentāls interaktīvu datu paneļu, tiešsaistes dizaina rīku vai pat vienkāršu spēļu veidošanai, kas prasa precīzu, kadru pa kadram renderēšanu, neatkarīgi no lietotāja ģeogrāfiskās atrašanās vietas vai ierīces iespējām.
3. Integrācija ar trešo pušu DOM bibliotēkām: Nevainojams tilts
Viens no pārliecinošākajiem iemesliem izmantot refs ir React integrācija ar ārējām JavaScript bibliotēkām, kas tieši manipulē ar DOM. Daudzas spēcīgas bibliotēkas, īpaši vecākas vai tās, kas koncentrējas uz specifiskiem renderēšanas uzdevumiem (piemēram, diagrammu veidošana, kartēšana vai bagātināta teksta rediģēšana), darbojas, pieņemot DOM elementu kā mērķi un pēc tam pašas pārvaldot tā saturu. React savā deklaratīvajā režīmā citādi konfliktētu ar šīm bibliotēkām, mēģinot kontrolēt to pašu DOM apakškoku. Refs novērš šo konfliktu, nodrošinot noteiktu 'konteineru' ārējai bibliotēkai.
import React from 'react';
import * as d3 from 'd3'; // Pieņemot, ka D3.js ir instalēts un importēts
class D3BarChart extends React.Component {
constructor(props) {
super(props);
this.chartContainerRef = React.createRef();
}
// Kad komponents iemontējas, uzzīmējiet diagrammu
componentDidMount() {
this.drawChart();
}
// Kad komponents atjaunojas (piem., props.data mainās), atjauniniet diagrammu
componentDidUpdate(prevProps) {
if (prevProps.data !== this.props.data) {
this.drawChart();
}
}
// Kad komponents tiek demontēts, notīriet D3 elementus, lai novērstu atmiņas noplūdes
componentWillUnmount() {
d3.select(this.chartContainerRef.current).selectAll('*').remove();
}
drawChart = () => {
const data = this.props.data || [40, 80, 20, 100, 60, 90]; // Noklusējuma dati
const node = this.chartContainerRef.current;
if (!node) return; // Pārliecinieties, ka ref ir pieejams
// Notīriet visus iepriekšējos D3 zīmētos diagrammas elementus
d3.select(node).selectAll('*').remove();
const margin = { top: 20, right: 20, bottom: 30, left: 40 };
const width = 460 - margin.left - margin.right;
const height = 300 - margin.top - margin.bottom;
const svg = d3.select(node)
.append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`);
// Iestatiet mērogus
const x = d3.scaleBand()
.range([0, width])
.padding(0.1);
const y = d3.scaleLinear()
.range([height, 0]);
x.domain(data.map((d, i) => i)); // Vienkāršības labad izmantojiet indeksu kā domēnu
y.domain([0, d3.max(data)]);
// Pievienojiet stabiņus
svg.selectAll('.bar')
.data(data)
.enter().append('rect')
.attr('class', 'bar')
.attr('x', (d, i) => x(i))
.attr('width', x.bandwidth())
.attr('y', d => y(d))
.attr('height', d => height - y(d))
.attr('fill', '#17a2b8');
// Pievienojiet X asi
svg.append('g')
.attr('transform', `translate(0,${height})`)
.call(d3.axisBottom(x));
// Pievienojiet Y asi
svg.append('g')
.call(d3.axisLeft(y));
};
render() {
return (
<div style={{ textAlign: 'center', margin: '30px auto', border: '1px solid #00a0b2', padding: '20px', borderRadius: '8px', background: '#e0f7fa' }}>
<h3>D3.js diagrammas integrācija ar React createRef</h3>
<p>Šo datu vizualizāciju renderē D3.js React pārvaldītā konteinerī.</p>
<div ref={this.chartContainerRef} /> // D3.js renderēs šajā div
<p><em>Šādu specializētu bibliotēku integrēšana ir būtiska datu ietilpīgām lietojumprogrammām, nodrošinot spēcīgus analītiskos rīkus lietotājiem dažādās nozarēs un reģionos.</em></p>
</div>
);
}
}
Šis plašais piemērs demonstrē D3.js stabiņu diagrammas integrāciju React klases komponentā. chartContainerRef nodrošina D3.js ar konkrēto DOM mezglu, kas nepieciešams tās renderēšanai. React pārvalda konteinera <div> dzīves ciklu, kamēr D3.js pārvalda tā iekšējo saturu. componentDidUpdate un componentWillUnmount metodes ir vitāli svarīgas, lai atjauninātu diagrammu, kad dati mainās, un lai veiktu nepieciešamo tīrīšanu, novēršot atmiņas noplūdes un nodrošinot atsaucīgu pieredzi. Šis modelis ir universāli pielietojams, ļaujot izstrādātājiem izmantot labāko no abām pasaulēm - React komponentu modeli un specializētas, augstas veiktspējas vizualizācijas bibliotēkas globāliem paneļiem un analītikas platformām.
4. Elementu izmēru vai pozīcijas mērīšana dinamiskiem izkārtojumiem
Ļoti dinamiskiem vai atsaucīgiem izkārtojumiem, vai arī, lai ieviestu tādas funkcijas kā virtualizēti saraksti, kas renderē tikai redzamos vienumus, ir svarīgi zināt precīzus elementu izmērus un pozīciju. Refs ļauj piekļūt getBoundingClientRect() metodei, kas sniedz šo svarīgo informāciju tieši no DOM.
import React from 'react';
class ElementDimensionLogger extends React.Component {
constructor(props) {
super(props);
this.measurableDivRef = React.createRef();
this.state = {
width: 0,
height: 0,
top: 0,
left: 0,
message: 'Noklikšķiniet uz pogas, lai mērītu!'
};
}
componentDidMount() {
// Sākotnējais mērījums bieži ir noderīgs, bet to var izraisīt arī lietotāja darbība
this.measureElement();
// Dinamiskiem izkārtojumiem varētu klausīties loga izmēru maiņas notikumus
window.addEventListener('resize', this.measureElement);
}
componentWillUnmount() {
window.removeEventListener('resize', this.measureElement);
}
measureElement = () => {
if (this.measurableDivRef.current) {
const rect = this.measurableDivRef.current.getBoundingClientRect();
this.setState({
width: Math.round(rect.width),
height: Math.round(rect.height),
top: Math.round(rect.top),
left: Math.round(rect.left),
message: 'Izmēri atjaunināti.'
});
} else {
this.setState({ message: 'Elements vēl nav renderēts.' });
}
};
render() {
const { width, height, top, left, message } = this.state;
const boxStyle = {
width: '70%',
minHeight: '150px',
border: '3px solid #ffc107',
margin: '25px auto',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
background: '#fff3cd',
borderRadius: '8px',
textAlign: 'center'
};
return (
<div style={{ maxWidth: '700px', margin: '30px auto', padding: '25px', boxShadow: '0 4px 12px rgba(0,0,0,0.08)', borderRadius: '10px', background: 'white' }}>
<h3>Elementu izmēru mērīšana ar createRef</h3>
<p>Šis piemērs dinamiski iegūst un parāda mērķa elementa izmēru un pozīciju.</p>
<div ref={this.measurableDivRef} style={boxStyle}>
<p><strong>Es esmu elements, kas tiek mērīts.</strong></p>
<p>Mainiet pārlūkprogrammas loga izmēru, lai redzētu, kā mainās mērījumi pēc atsvaidzināšanas/manuālas iedarbināšanas.</p>
</div>
<button
onClick={this.measureElement}
style={{ padding: '10px 20px', background: '#6c757d', color: 'white', border: 'none', borderRadius: '5px', cursor: 'pointer', marginBottom: '15px' }}
>
Mērīt tagad
</button>
<div style={{ background: '#f0f0f0', padding: '15px', borderRadius: '6px' }}>
<p><strong>Tiešraides izmēri:</strong></p>
<ul style={{ listStyleType: 'none', padding: 0, textAlign: 'left', margin: '0 auto', maxWidth: '300px' }}>
<li>Platums: <b>{width}px</b></li>
<li>Augstums: <b>{height}px</b></li>
<li>Augšējā pozīcija (skatlogs): <b>{top}px</b></li>
<li>Kreisā pozīcija (skatlogs): <b>{left}px</b></li>
</ul>
<p><em>Precīza elementu mērīšana ir kritiska atsaucīgiem dizainiem un veiktspējas optimizācijai dažādās ierīcēs visā pasaulē.</em></p>
</div>
</div>
);
}
}
Šis komponents izmanto createRef, lai iegūtu getBoundingClientRect() no div elementa, nodrošinot tā reāllaika izmērus un pozīciju. Šī informācija ir nenovērtējama, lai ieviestu sarežģītas izkārtojuma korekcijas, noteiktu redzamību virtualizētā ritināšanas sarakstā vai pat nodrošinātu, ka elementi atrodas noteiktā skatloga apgabalā. Globālai auditorijai, kur ekrāna izmēri, izšķirtspējas un pārlūkprogrammu vides ir ļoti dažādas, precīza izkārtojuma kontrole, pamatojoties uz faktiskajiem DOM mērījumiem, ir galvenais faktors, lai nodrošinātu konsekventu un augstas kvalitātes lietotāja pieredzi.
Labākās prakses un brīdinājumi, lietojot `createRef`
Lai gan createRef piedāvā spēcīgu imperatīvo kontroli, tā nepareiza lietošana var novest pie koda, kas ir grūti pārvaldāms un atkļūdojams. Labāko prakšu ievērošana ir būtiska, lai atbildīgi izmantotu tās spēku.
1. Dodiet priekšroku deklaratīvām pieejām: Zelta likums
Vienmēr atcerieties, ka refs ir "avārijas izeja", nevis galvenais mijiedarbības veids React. Pirms ķerties pie ref, pajautājiet sev: vai to var panākt ar stāvokli un props? Ja atbilde ir jā, tad tas gandrīz vienmēr ir labāks, vairāk "React-idiomatisks" risinājums. Piemēram, ja vēlaties mainīt ievades lauka vērtību, izmantojiet kontrolētus komponentus ar stāvokli, nevis ref, lai tieši iestatītu inputRef.current.value.
2. Refs ir paredzēti imperatīvām mijiedarbībām, nevis stāvokļa pārvaldībai
Refs ir vispiemērotākie uzdevumiem, kas ietver tiešas, imperatīvas darbības ar DOM elementiem vai komponentu instancēm. Tās ir komandas: "fokusēt šo ievades lauku", "atskaņot šo video", "ritināt uz šo sadaļu". Tie nav paredzēti, lai mainītu komponenta deklaratīvo lietotāja saskarni, pamatojoties uz stāvokli. Tieša elementa stila vai satura manipulēšana, izmantojot ref, ja to varētu kontrolēt ar props vai stāvokli, var novest pie tā, ka React virtuālais DOM vairs nav sinhronizēts ar faktisko DOM, izraisot neparedzamu uzvedību un renderēšanas problēmas.
3. Refs un funkcionālie komponenti: Izmantojiet `useRef` un `forwardRef`
Mūsdienu React izstrādē funkcionālajos komponentos React.createRef() nav rīks, ko jūs izmantosiet. Tā vietā jūs paļausities uz useRef āķi. useRef āķis nodrošina maināmu ref objektu, līdzīgu createRef, kura .current īpašību var izmantot tām pašām imperatīvajām mijiedarbībām. Tas saglabā savu vērtību starp komponenta atkārtotām renderēšanām, neizraisot pašu atkārtotu renderēšanu, padarot to perfektu, lai turētu atsauci uz DOM mezglu vai jebkuru maināmu vērtību, kam jāpastāv starp renderēšanām.
import React, { useRef, useEffect } from 'react';
function FunctionalComponentWithRef() {
const myInputRef = useRef(null); // Inicializēt ar null
useEffect(() => {
// Tas tiek izpildīts pēc komponenta iemontēšanas
if (myInputRef.current) {
myInputRef.current.focus();
console.log('Functional component input focused!');
}
}, []); // Tukšs atkarību masīvs nodrošina, ka tas tiek izpildīts tikai vienreiz iemontējot
const handleLogValue = () => {
if (myInputRef.current) {
alert(`Input value: ${myInputRef.current.value}`);
}
};
return (
<div style={{ margin: '20px', padding: '20px', border: '1px solid #009688', borderRadius: '8px', background: '#e0f2f1' }}>
<h3>useRef izmantošana funkcionālā komponentā</h3>
<label htmlFor="funcInput">Ierakstiet kaut ko:</label><br />
<input id="funcInput" type="text" ref={myInputRef} placeholder="Man automātiski iestata fokusu!" style={{ padding: '8px', margin: '10px 0', borderRadius: '4px', border: '1px solid #ccc' }} /><br />
<button onClick={handleLogValue} style={{ padding: '10px 15px', background: '#009688', color: 'white', border: 'none', borderRadius: '5px', cursor: 'pointer' }}>
Reģistrēt ievades vērtību
</button>
<p><em>Jauniem projektiem `useRef` ir idiomātiska izvēle refs funkcionālajos komponentos.</em></p>
</div>
);
}
Ja jums nepieciešams, lai vecākkomponents iegūtu ref uz DOM elementu iekšā funkcionālā bērnkomponentā, tad React.forwardRef ir jūsu risinājums. Tas ir augstākās kārtas komponents, kas ļauj jums "pārsūtīt" ref no vecāka uz vienu no tā bērnu DOM elementiem, saglabājot funkcionālā komponenta iekapsulāciju, vienlaikus nodrošinot imperatīvu piekļuvi, kad tas ir nepieciešams.
import React, { useRef, useEffect } from 'react';
// Funkcionāls komponents, kas skaidri pārsūta ref uz savu vietējo ievades elementu
const ForwardedInput = React.forwardRef((props, ref) => (
<input type="text" ref={ref} className="forwarded-input" placeholder={props.placeholder} style={{ padding: '10px', margin: '8px 0', border: '1px solid #ccc', borderRadius: '4px', width: '100%' }} />
));
class ParentComponentUsingForwardRef extends React.Component {
constructor(props) {
super(props);
this.parentInputRef = React.createRef();
}
componentDidMount() {
if (this.parentInputRef.current) {
this.parentInputRef.current.focus();
console.log('Input inside functional component focused from parent (class component) via forwarded ref!');
}
}
render() {
return (
<div style={{ margin: '20px', padding: '20px', border: '1px solid #6f42c1', borderRadius: '8px', background: '#f5eef9' }}>
<h3>Ref pārsūtīšanas piemērs ar createRef (vecākkomponenta klase)</h3>
<label>Ievadiet datus:</label>
<ForwardedInput ref={this.parentInputRef} placeholder="Šis ievades lauks ir funkcionāla komponenta iekšienē" />
<p><em>Šis modelis ir būtisks, lai izveidotu atkārtoti lietojamas komponentu bibliotēkas, kurām nepieciešams atklāt tiešu DOM piekļuvi.</em></p>
</div>
);
}
}
Tas demonstrē, kā klases komponents, izmantojot createRef, var efektīvi mijiedarboties ar DOM elementu, kas ligzdots funkcionālā komponentā, izmantojot forwardRef. Tas padara funkcionālos komponentus tikpat spējīgus piedalīties imperatīvās mijiedarbībās, kad tas ir nepieciešams, nodrošinot, ka mūsdienu React koda bāzes joprojām var gūt labumu no refs.
4. Kad nelietot Refs: React integritātes saglabāšana
- Lai kontrolētu bērnkomponenta stāvokli: Nekad neizmantojiet ref, lai tieši nolasītu vai atjauninātu bērnkomponenta stāvokli. Tas apiet React stāvokļa pārvaldību, padarot jūsu lietojumprogrammu neparedzamu. Tā vietā nododiet stāvokli uz leju kā props un izmantojiet atzvanu funkcijas, lai ļautu bērniem pieprasīt stāvokļa izmaiņas no vecākiem.
- Kā props aizstājēju: Lai gan jūs varat izsaukt metodes bērnkomponenta klasē caur ref, apsveriet, vai notikumu apstrādātāja nodošana kā prop bērnam nesasniegtu to pašu mērķi "React-idiomatiskākā" veidā. Props veicina skaidru datu plūsmu un padara komponentu mijiedarbību caurspīdīgu.
-
Vienkāršām DOM manipulācijām, ko React var apstrādāt: Ja vēlaties mainīt elementa tekstu, stilu vai pievienot/noņemt klasi, pamatojoties uz stāvokli, dariet to deklaratīvi. Piemēram, lai pārslēgtu klasi
active, nosacīti lietojiet to JSX:<div className={isActive ? 'active' : ''}>, nevisdivRef.current.classList.add('active').
5. Veiktspējas apsvērumi un globālā sasniedzamība
Lai gan pats createRef ir veiktspējīgs, darbības, kas veiktas, izmantojot current, var būtiski ietekmēt veiktspēju. Lietotājiem ar zemākas klases ierīcēm vai lēnākiem tīkla savienojumiem (kas ir izplatīti daudzviet pasaulē) neefektīvas DOM manipulācijas var izraisīt raustīšanos, nereaģējošas lietotāja saskarnes un sliktu lietotāja pieredzi. Lietojot refs tādiem uzdevumiem kā animācijas, sarežģīti izkārtojuma aprēķini vai smagu trešo pušu bibliotēku integrēšana:
-
Debounce/Throttle notikumi: Ja izmantojat refs, lai mērītu izmērus
window.resizevaiscrollnotikumiem, nodrošiniet, ka šie apstrādātāji ir debounced vai throttled, lai novērstu pārmērīgu funkciju izsaukumu un DOM lasīšanu. -
Grupējiet DOM lasīšanas/rakstīšanas operācijas: Izvairieties no DOM lasīšanas operāciju (piemēram,
getBoundingClientRect()) un DOM rakstīšanas operāciju (piemēram, stilu iestatīšanas) sajaukšanas. Tas var izraisīt izkārtojuma trīcēšanu (layout thrashing). Rīki, piemēram,fastdom, var palīdzēt to efektīvi pārvaldīt. -
Atlieciet nekritiskas operācijas: Izmantojiet
requestAnimationFrameanimācijām unsetTimeout(..., 0)vairequestIdleCallbackmazāk kritiskām DOM manipulācijām, lai nodrošinātu, ka tās nebloķē galveno pavedienu un neietekmē atsaucību. - Izvēlieties gudri: Dažreiz trešās puses bibliotēkas veiktspēja var būt vājais posms. Izvērtējiet alternatīvas vai apsveriet šādu komponentu slinko ielādi lietotājiem ar lēnākiem savienojumiem, nodrošinot, ka pamata pieredze visā pasaulē paliek veiktspējīga.
`createRef` pret atzvanu Refs (Callback Refs) pret `useRef`: Detalizēts salīdzinājums
React savas evolūcijas gaitā ir piedāvājis dažādus veidus, kā rīkoties ar refs. Izpratne par katra niansēm ir galvenais, lai izvēlētos vispiemērotāko metodi jūsu konkrētajam kontekstam.
1. `React.createRef()` (Klašu komponenti - Mūsdienīgi)
-
Mehānisms: Izveido ref objektu (
{ current: null }) komponenta instances konstruktorā. React piešķir DOM elementu vai komponenta instanci.currentīpašībai pēc iemontēšanas. - Primārais lietojums: Ekskluzīvi klašu komponentos. Tas tiek inicializēts vienreiz katrai komponenta instancei.
-
Ref aizpildīšana:
.currenttiek iestatīts uz elementu/instanci pēc komponenta iemontēšanas un atiestatīts uznulldemontējot. - Vislabāk piemērots: Visām standarta ref prasībām klašu komponentos, kur nepieciešams atsaukties uz DOM elementu vai bērnkomponenta klases instanci.
- Priekšrocības: Skaidra, tieša objektorientēta sintakse. Nav jāuztraucas par iekļautu funkciju atkārtotu izveidi, kas izraisa papildu izsaukumus (kā tas var notikt ar atzvanu refs).
- Trūkumi: Nav lietojams ar funkcionāliem komponentiem. Ja nav inicializēts konstruktorā (piemēram, renderēšanas laikā), katrā renderēšanā var tikt izveidots jauns ref objekts, kas var radīt potenciālas veiktspējas problēmas vai nepareizas ref vērtības. Jāatceras piešķirt instances īpašībai.
2. Atzvanu Refs (Callback Refs) (Klašu un funkcionālie komponenti - Elastīgi/Mantoti)
-
Mehānisms: Jūs nododat funkciju tieši
refprop. React izsauc šo funkciju ar iemontēto DOM elementu vai komponenta instanci, un vēlāk arnull, kad tas tiek demontēts. -
Primārais lietojums: Var izmantot gan klašu, gan funkcionālajos komponentos. Klašu komponentos atzvanu funkcija parasti ir saistīta ar
thisvai definēta kā bultiņfunkcijas klases īpašība. Funkcionālajos komponentos tā bieži tiek definēta iekļauti vai memoizēta. -
Ref aizpildīšana: Atzvanu funkciju tieši izsauc React. Jūs esat atbildīgs par atsauces glabāšanu (piemēram,
this.myInput = element;). -
Vislabāk piemērots: Scenārijiem, kas prasa smalkāku kontroli pār to, kad refs tiek iestatīti un atiestatīti, vai sarežģītākiem modeļiem, piemēram, dinamiskiem ref sarakstiem. Tas bija galvenais veids, kā pārvaldīt refs pirms
createRefunuseRef. - Priekšrocības: Nodrošina maksimālu elastību. Dod jums tūlītēju piekļuvi ref, kad tas ir pieejams (atzvanu funkcijas ietvaros). Var izmantot, lai glabātu refs masīvā vai kartē dinamisku elementu kolekcijām.
-
Trūkumi: Ja atzvanu funkcija ir definēta iekļauti
rendermetodē (piemēram,ref={el => this.myRef = el}), tā tiks izsaukta divreiz atjaunināšanas laikā (vienreiz arnull, tad ar elementu), kas var izraisīt veiktspējas problēmas vai neparedzētas blakusparādības, ja netiek rūpīgi apstrādāts (piemēram, padarot atzvanu par klases metodi vai izmantojotuseCallbackfunkcionālajos komponentos).
class CallbackRefDetailedExample extends React.Component {
constructor(props) {
super(props);
this.inputElement = null;
}
// Šo metodi izsauks React, lai iestatītu ref
setInputElementRef = element => {
if (element) {
console.log('Ref element is:', element);
}
this.inputElement = element; // Saglabājiet faktisko DOM elementu
};
componentDidMount() {
if (this.inputElement) {
this.inputElement.focus();
}
}
render() {
return (
<div>
<label>Atzvanu Ref ievade:</label>
<input type="text" ref={this.setInputElementRef} />
</div>
);
}
}
3. `useRef` āķis (Funkcionālie komponenti - Mūsdienīgi)
-
Mehānisms: React āķis, kas atgriež maināmu ref objektu (
{ current: initialValue }). Atgrieztais objekts saglabājas visu funkcionālā komponenta dzīves laiku. - Primārais lietojums: Ekskluzīvi funkcionālajos komponentos.
-
Ref aizpildīšana: Līdzīgi kā
createRef, React piešķir DOM elementu vai komponenta instanci (ja pārsūtīts).currentīpašībai pēc iemontēšanas un iestata to uznulldemontējot..currentvērtību var arī manuāli atjaunināt. - Vislabāk piemērots: Visai ref pārvaldībai funkcionālajos komponentos. Noderīgs arī, lai turētu jebkuru maināmu vērtību, kam jāpastāv starp renderēšanām, neizraisot atkārtotu renderēšanu (piemēram, taimera ID, iepriekšējās vērtības).
- Priekšrocības: Vienkāršs, idiomātisks āķiem. Ref objekts saglabājas starp renderēšanām, izvairoties no atkārtotas izveides problēmām. Var glabāt jebkuru maināmu vērtību, ne tikai DOM mezglus.
-
Trūkumi: Darbojas tikai funkcionālajos komponentos. Nepieciešams skaidrs
useEffectdzīves cikla saistītām ref mijiedarbībām (piemēram, fokusēšanai iemontējot).
Kopsavilkumā:
-
Ja rakstāt klases komponentu un jums ir nepieciešams ref,
React.createRef()ir ieteicamākā un skaidrākā izvēle. -
Ja rakstāt funkcionālu komponentu un jums ir nepieciešams ref,
useRefāķis ir mūsdienīgs, idiomātisks risinājums. - Atzvanu refs joprojām ir derīgi, bet parasti ir izvērstāki un pakļauti smalkām problēmām, ja nav rūpīgi ieviesti. Tie ir noderīgi sarežģītos scenārijos vai strādājot ar vecākām koda bāzēm vai kontekstiem, kur āķi nav pieejami.
-
Lai nodotu refs caur komponentiem (īpaši funkcionāliem),
React.forwardRef()ir būtisks, bieži lietots kopā arcreateRefvaiuseRefvecākkomponentā.
Globāli apsvērumi un uzlabota pieejamība ar Refs
Lai gan bieži tiek apspriests tehniskā vakuumā, refs izmantošanai globāli orientētā lietojumprogrammu kontekstā ir svarīgas sekas, īpaši attiecībā uz veiktspēju un pieejamību dažādiem lietotājiem.
1. Veiktspējas optimizācija dažādām ierīcēm un tīkliem
Paša createRef ietekme uz saišķa izmēru ir minimāla, jo tā ir maza daļa no React kodola. Tomēr darbībām, ko veicat ar current īpašību, var būt būtiska ietekme uz veiktspēju. Lietotājiem ar zemākas klases ierīcēm vai lēnākiem tīkla savienojumiem (kas ir izplatīti daudzviet pasaulē), neefektīvas DOM manipulācijas var izraisīt raustīšanos, nereaģējošas lietotāja saskarnes un sliktu lietotāja pieredzi. Lietojot refs tādiem uzdevumiem kā animācijas, sarežģīti izkārtojuma aprēķini vai smagu trešo pušu bibliotēku integrēšana:
-
Debounce/Throttle notikumi: Ja izmantojat refs, lai mērītu izmērus
window.resizevaiscrollnotikumiem, nodrošiniet, ka šie apstrādātāji ir debounced vai throttled, lai novērstu pārmērīgu funkciju izsaukumu un DOM lasīšanu. -
Grupējiet DOM lasīšanas/rakstīšanas operācijas: Izvairieties no DOM lasīšanas operāciju (piemēram,
getBoundingClientRect()) un DOM rakstīšanas operāciju (piemēram, stilu iestatīšanas) sajaukšanas. Tas var izraisīt izkārtojuma trīcēšanu (layout thrashing). Rīki, piemēram,fastdom, var palīdzēt to efektīvi pārvaldīt. -
Atlieciet nekritiskas operācijas: Izmantojiet
requestAnimationFrameanimācijām unsetTimeout(..., 0)vairequestIdleCallbackmazāk kritiskām DOM manipulācijām, lai nodrošinātu, ka tās nebloķē galveno pavedienu un neietekmē atsaucību. - Izvēlieties gudri: Dažreiz trešās puses bibliotēkas veiktspēja var būt vājais posms. Izvērtējiet alternatīvas vai apsveriet šādu komponentu slinko ielādi lietotājiem ar lēnākiem savienojumiem, nodrošinot, ka pamata pieredze visā pasaulē paliek veiktspējīga.
2. Pieejamības uzlabošana (ARIA atribūti un navigācija ar tastatūru)
Refs ir noderīgi, lai veidotu ļoti pieejamas tīmekļa lietojumprogrammas, īpaši, veidojot pielāgotus lietotāja saskarnes komponentus, kuriem nav vietējo pārlūkprogrammas ekvivalentu, vai arī, ja tiek pārrakstīta noklusējuma uzvedība. Globālai auditorijai Tīmekļa satura pieejamības vadlīniju (WCAG) ievērošana ir ne tikai laba prakse, bet bieži vien arī juridiska prasība. Refs nodrošina:
- Programmatiska fokusa pārvaldība: Kā redzams ar ievades laukiem, refs ļauj iestatīt fokusu, kas ir būtiski tastatūras lietotājiem un ekrāna lasītāju navigācijai. Tas ietver fokusa pārvaldību modālos logos, nolaižamajās izvēlnēs vai interaktīvos sīkrīkos.
-
Dinamiski ARIA atribūti: Jūs varat izmantot refs, lai dinamiski pievienotu vai atjauninātu ARIA (Accessible Rich Internet Applications) atribūtus (piemēram,
aria-expanded,aria-controls,aria-live) DOM elementos. Tas sniedz semantisku informāciju palīgtehnoloģijām, kas, iespējams, nav secināma tikai no vizuālās lietotāja saskarnes.class CollapsibleSection extends React.Component {
constructor(props) {
super(props);
this.buttonRef = React.createRef();
this.state = { isExpanded: false };
}
toggleExpanded = () => {
this.setState(prevState => ({ isExpanded: !prevState.isExpanded }), () => {
if (this.buttonRef.current) {
// Dinamiski atjauniniet ARIA atribūtu, pamatojoties uz stāvokli
this.buttonRef.current.setAttribute('aria-expanded', this.state.isExpanded);
}
});
};
componentDidMount() {
if (this.buttonRef.current) {
this.buttonRef.current.setAttribute('aria-controls', `section-${this.props.id}`);
this.buttonRef.current.setAttribute('aria-expanded', this.state.isExpanded);
}
}
render() {
const { id, title, children } = this.props;
const { isExpanded } = this.state;
return (
<div style={{ margin: '20px auto', maxWidth: '600px', border: '1px solid #0056b3', borderRadius: '8px', background: '#e7f0fa', overflow: 'hidden' }}>
<h4>
<button
ref={this.buttonRef} // Ref uz pogu ARIA atribūtiem
onClick={this.toggleExpanded}
style={{ background: 'none', border: 'none', padding: '15px 20px', width: '100%', textAlign: 'left', cursor: 'pointer', fontSize: '1.2em', color: '#0056b3', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}
id={`section-header-${id}`}
>
{title} <span>▼</span>
</button>
</h4>
{isExpanded && (
<div id={`section-${id}`} role="region" aria-labelledby={`section-header-${id}`} style={{ padding: '0 20px 20px', borderTop: '1px solid #a7d9f7' }}>
{children}
</div>
)}
</div>
);
}
} - Tastatūras mijiedarbības kontrole: Pielāgotām nolaižamajām izvēlnēm, slīdņiem vai citiem interaktīviem elementiem jums var būt nepieciešams ieviest specifiskus tastatūras notikumu apstrādātājus (piemēram, bultiņu taustiņus navigācijai sarakstā). Refs nodrošina piekļuvi mērķa DOM elementam, kur šos notikumu klausītājus var pievienot un pārvaldīt.
Pārdomāti pielietojot refs, izstrādātāji var nodrošināt, ka viņu lietojumprogrammas ir lietojamas un iekļaujošas cilvēkiem ar invaliditāti visā pasaulē, ievērojami paplašinot to globālo sasniedzamību un ietekmi.
3. Internacionalizācija (I18n) un lokalizētas mijiedarbības
Strādājot ar internacionalizāciju (i18n), refs var spēlēt smalku, bet svarīgu lomu. Piemēram, valodās, kurās izmanto rakstību no labās uz kreiso (RTL) (piemēram, arābu, ebreju vai persiešu), dabiskā tabulēšanas secība un ritināšanas virziens var atšķirties no valodām, kas raksta no kreisās uz labo (LTR). Ja jūs programmatiski pārvaldāt fokusu vai ritināšanu, izmantojot refs, ir svarīgi nodrošināt, ka jūsu loģika ievēro dokumenta vai elementa teksta virzienu (dir atribūtu).
- RTL apzinoša fokusa pārvaldība: Lai gan pārlūkprogrammas parasti pareizi apstrādā noklusējuma tabulēšanas secību RTL, ja jūs īstenojat pielāgotus fokusa slazdus vai secīgu fokusēšanu, rūpīgi pārbaudiet savu uz ref balstīto loģiku RTL vidēs, lai nodrošinātu konsekventu un intuitīvu pieredzi.
-
Izkārtojuma mērīšana RTL: Lietojot
getBoundingClientRect()caur ref, ņemiet vērā, kaleftunrightīpašības ir relatīvas attiecībā pret skatlogu. Izkārtojuma aprēķiniem, kas atkarīgi no vizuālā sākuma/beigām, apsverietdocument.dirvai elementa aprēķināto stilu, lai pielāgotu savu loģiku RTL izkārtojumiem. - Trešo pušu bibliotēku integrācija: Pārliecinieties, ka visas trešo pušu bibliotēkas, kas integrētas, izmantojot refs (piemēram, diagrammu bibliotēkas), pašas ir i18n apzinošas un pareizi apstrādā RTL izkārtojumus, ja jūsu lietojumprogramma tos atbalsta. Atbildība par to bieži gulstas uz izstrādātāju, kurš integrē bibliotēku React komponentā.
Noslēgums: Imperatīvās kontroles apgūšana ar `createRef` globālām lietojumprogrammām
React.createRef() ir vairāk nekā tikai "avārijas izeja" React; tas ir vitāli svarīgs rīks, kas mazina plaisu starp React spēcīgo deklaratīvo paradigmu un pārlūkprogrammas DOM mijiedarbības imperatīvo realitāti. Lai gan tā lomu jaunākos funkcionālajos komponentos lielā mērā ir pārņēmis useRef āķis, createRef joprojām ir standarts un visidiomatiskākais veids, kā pārvaldīt refs klašu komponentos, kas joprojām veido būtisku daļu no daudzām uzņēmumu lietojumprogrammām visā pasaulē.
Rūpīgi izprotot tā izveidi, pievienošanu un .current īpašības kritisko lomu, izstrādātāji var pārliecinoši risināt tādus izaicinājumus kā programmatiska fokusa pārvaldība, tieša multivides kontrole, nevainojama integrācija ar dažādām trešo pušu bibliotēkām (no D3.js diagrammām līdz pielāgotiem bagātinātā teksta redaktoriem) un precīza elementu izmēru mērīšana. Šīs spējas nav tikai tehniski varoņdarbi; tās ir fundamentālas, lai veidotu lietojumprogrammas, kas ir veiktspējīgas, pieejamas un lietotājam draudzīgas plašā globālo lietotāju, ierīču un kultūras kontekstu spektrā.
Atcerieties lietot šo spēku apdomīgi. Vienmēr dodiet priekšroku React deklaratīvajai stāvokļa un prop sistēmai. Kad imperatīva kontrole ir patiesi nepieciešama, createRef (klašu komponentiem) vai useRef (funkcionāliem komponentiem) piedāvā stabilu un labi definētu mehānismu, lai to sasniegtu. Refs apgūšana dod jums iespēju tikt galā ar mūsdienu tīmekļa izstrādes malējiem gadījumiem un sarežģītībām, nodrošinot, ka jūsu React lietojumprogrammas var sniegt izcilu lietotāja pieredzi jebkurā pasaules vietā, vienlaikus saglabājot React elegantās, uz komponentiem balstītās arhitektūras galvenās priekšrocības.
Tālākā mācīšanās un izpēte
- React oficiālā dokumentācija par Refs: Lai iegūtu visjaunāko informāciju tieši no avota, skatiet <em>https://react.dev/learn/manipulating-the-dom-with-refs</em>
- Izpratne par React `useRef` āķi: Lai dziļāk iedziļinātos funkcionālā komponenta ekvivalentā, izpētiet <em>https://react.dev/reference/react/useRef</em>
- Ref pārsūtīšana ar `forwardRef`: Uzziniet, kā efektīvi nodot refs caur komponentiem: <em>https://react.dev/reference/react/forwardRef</em>
- Tīmekļa satura pieejamības vadlīnijas (WCAG): Būtiski globālai tīmekļa izstrādei: <em>https://www.w3.org/WAI/WCAG22/quickref/</em>
- React veiktspējas optimizācija: Labākās prakses augstas veiktspējas lietotnēm: <em>https://react.dev/learn/optimizing-performance</em>